package com.example.mybatis_plus_use.Interceptor;

import com.example.mybatis_plus_use.entity.User;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.crypto.SecretKey;
import java.util.Date;

/**
 * JWT工具类
 * 用于 生成WT令牌  解析WT令牌  验证JWT令牌
 */
@Component
public class JwtUtil {
    /**
     * JWT加密密钥
     * 注意：实际项目中应该配置在配置文件中，不应该硬编码
     * 密钥长度至少需要256位（32字节）以满足HS256算法的要求
     */
    private static final String SECRET_KEY = "your-secret-key-must-be-at-least-256-bits-long";

    /**
     * token有效期，单位：毫秒
     * 当前设置为24小时
     */
    private static final long EXPIRE_TIME = 24 * 60 * 60 * 1000;

    /**
     * 使用密钥生成加密密钥对象
     * HMAC-SHA算法的密钥
     */
    private static final SecretKey key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes());

    /**
     * 生成JWT令牌
     *
     * @param username 用户名，用于生成token的主题
     * @return 生成的JWT字符串
     */
    public static String generateToken(String username) {
        Date now = new Date();  // 当前时间
        Date expiration = new Date(now.getTime() + EXPIRE_TIME);  // 过期时间

        return Jwts.builder()
                .setSubject(username)     // 设置主题（通常是用户名）sub
                .setIssuedAt(now)         // 设置签发时间iat
                .setExpiration(expiration) // 设置过期时间exp
                .signWith(key)            // 使用密钥签名
                .compact();               // 生成JWT字符串
    }

    /**
     * 解析JWT令牌
     *
     * @param token JWT字符串
     * @return JWT中的声明（payload部分）
     * @throws JwtException 如果token无效或已过期
     */
    public static Claims parseToken(String token) {
        try{
            return Jwts.parserBuilder()
                    .setSigningKey(key)   // 设置签名密钥
                    .build()              // 构建解析器
                    .parseClaimsJws(token)// 解析JWT
                    .getBody();           // 获取JWT中的声明（payload部分）
        }catch (Exception e){
            return null;
        }

    }

    /**
     * 验证JWT令牌是否有效
     *
     * @param token JWT字符串
     * @return true:有效 false:无效
     */
    public static boolean validateToken(String token) {
        try {
            Jwts.parserBuilder()
                    .setSigningKey(key)
                    .build()
                    .parseClaimsJws(token);// 解析JWT
            return true;  // 解析成功，token有效
        } catch (JwtException e) {
            return false; // 解析失败，token无效或已过期
        }
    }
    /**
     * 获取当前登录用户信息
     * 从当前请求的JWT token中解析用户数据
     *
     * @return 当前登录的用户对象
     * @throws RuntimeException 当不在Web上下文中、未登录或token无效时抛出
     */
    public static User  getCurrentUser() {
        // 从当前请求的上下文信息获取当前请求属性(就是在接口方法中才能用一下的)
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        if (attributes == null) {
            throw new RuntimeException("非Web上下文无法获取用户信息");
        }

        // 从请求头中获取token，从属性集合中获取具体的请求对象
        HttpServletRequest request = attributes.getRequest();
        String token = request.getHeader("Authorization");

        // 验证token是否存在且格式正确
        if (token == null || !token.startsWith("Bearer ")) {
            throw new RuntimeException("未登录或token已失效");
        }

        // 去除Bearer前缀，解析token
        token = token.substring(7);//Authorazation字段前面是Bearer前缀，后面才是token
        Claims claims = parseToken(token);

        // 从token中的claims构建并返回用户对象
        return User.builder()
                .username(claims.getSubject())    // 用户名
                .id(claims.get("Id", Integer.class))    // 用户ID
                .email(claims.get("email", String.class))    // 邮箱
                .build();
    }
    //获取tokenpayload中的用户名
    public static String getUsernameFromToken(String token) {
        Claims claims = parseToken(token);// 解析token后获取的是payload部分，放入claim对象中
        return claims.getSubject();// 获取用户名
    }
    //token解析出来要用claim对象接收
}